package de.gwtprime.server.servlets.cron;

import java.io.IOException;
import java.util.Date;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.log4j.Logger;
import org.json.simple.JSONArray;
import org.json.simple.JSONObject;

import com.google.appengine.api.memcache.MemcacheService;
import com.google.appengine.api.memcache.MemcacheServiceFactory;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.JsonElement;
import com.google.gson.JsonParser;

import de.gwtprime.server.ChannelManager;
import de.gwtprime.server.model.Transaction;
import de.gwtprime.server.model.User2;
import de.gwtprime.server.util.RPCClient;
import de.gwtprime.shared.TransactionType;
import de.gwtprime.shared.util.UnitConverter;
import de.gwtprime.shared.util.UnitConverter.Unit;

/**
 * possible parameters:
 * debug=true -> print out debbugging infos
 * numTransactions = 1
 * @author jan
 *
 */
public class BalanceCheck extends HttpServlet{

	/**
	 * Serial version ID
	 */
	private static final long serialVersionUID = 1L;
	
	/**
	 * Logger
	 */
	private static Logger logger = Logger.getLogger(BalanceCheck.class);

	@Override
	protected void doGet(HttpServletRequest req, HttpServletResponse resp)
			throws ServletException, IOException {
		
		resp.setContentType("text/plain");
		
		Boolean debug = Boolean.valueOf(req.getParameter("debug"));
		
		Integer numberOfTransactions = null;
		try {
			numberOfTransactions = Integer.parseInt(req.getParameter("numTransactions"));
		} catch (Exception e) {
			// TODO: handle exception
		}
		
		
		resp.getWriter().println("Debug: "+debug);
		resp.getWriter().println("Number transactions: "+numberOfTransactions);
		
		long start = System.currentTimeMillis();
		
		resp.getWriter().println("Starting balance check...");

		JSONArray s = null;
		try {
			s = RPCClient.getInstance().listtransactions(numberOfTransactions);
		} catch (Exception e) {
			resp.getWriter().println(e);
		}
		
		Gson gson = new GsonBuilder().setPrettyPrinting().create();
		JsonParser jp = new JsonParser();
		JsonElement je = jp.parse(s.toString());
		String prettyJsonString = gson.toJson(je);
		if(debug)
			resp.getWriter().println(prettyJsonString);
		MemcacheService cache = MemcacheServiceFactory.getMemcacheService();
	    //.setErrorHandler(ErrorHandlers.getConsistentLogAndContinue(Level.INFO));
		//cache.put("lastDetectedTransaction", "0e77e2ef0b1c297325137f59ee9c38e495a023459cfc4e0892908878b75cf8e3");
		String lastTransaction = (String)cache.get("lastDetectedTransaction");
		
		resp.getWriter().println("Last transaction from cache: "+ lastTransaction);
		
		for(Object o : s){

			JSONObject json = (JSONObject)o;

			Long id;
			try{
				id = Long.parseLong(json.get("account").toString());
			}catch(Exception e){
				je = jp.parse(json.toString());
				logger.error("Could not get account for transaction: "+gson.toJson(je));
				continue;
			}
			Double ammount = Double.parseDouble(json.get("amount").toString());

			Transaction transaction = new Transaction();

			transaction.setAmount(ammount);
			transaction.setAddress(json.get("address").toString());
			transaction.setTransactionId(json.get("txid").toString());
			transaction.setTime(new Date(Long.parseLong(json.get("time").toString())*1000));
			transaction.setTimeReceived(new Date(Long.parseLong(json.get("timereceived").toString())*1000));
			transaction.setType(json.get("category").equals("receive") ? TransactionType.DEPOSIT : TransactionType.WITHDRAW);
			
			if(numberOfTransactions!=null &&
					numberOfTransactions == 1 &&
					transaction.getTransactionId() != null  && 
					transaction.getTransactionId().equals(lastTransaction)){
				resp.getWriter().println("skipped transaction: "+transaction.getTransactionId());
				long after = System.currentTimeMillis();
				resp.getWriter().println(UnitConverter.convertInputFitting(after-start, Unit.MILLISECONDS));
				return;
			}
			
			User2 u = User2.findUser2(id);

			if(u!=null && !u.containsTxd(transaction)){
				u.addTransaction(transaction);
				
				u.persist();

				resp.getWriter().println("New balance "+(u.getBalanceBitcoin()));
				resp.getWriter().println("Updated user "+u);
				
				// Push information about new transaction to the affected client
				if(transaction.getType()==TransactionType.DEPOSIT){
					ChannelManager.pushToClient(u.getId().toString(), "newTransactionAvailable");
				}
				
				cache.put("lastDetectedTransaction", transaction.getTransactionId());
				
			}else if(numberOfTransactions!=null &&
					numberOfTransactions == 1 && lastTransaction==null){
				cache.put("lastDetectedTransaction", transaction.getTransactionId());
			}
		}
		resp.getWriter().println("done!");
		
		long after = System.currentTimeMillis();
		
		resp.getWriter().println(UnitConverter.convertInputFitting(after-start, Unit.MILLISECONDS));
	}
}
